11.4 性能监控

引发性能问题的原因无外乎执行时间过长、内存占用过多,以及意外阻塞。通过捕获或监控相关执行状态数据,就可定位引发问题的原因,从而有针对性改进算法。

有两种捕获方式:首先,在测试时输出并保存相关数据,进行初期评估。其次,在运行阶段通过Web接口获得实时数据,分析一段时间内的健康状况。除此之外,我们还可使用自定义计数器(expvar)提供更多与逻辑相关的参考数据。

拿标准库现有的Benchmark做演示:

$go test-run NONE-bench. -memprofile mem.out-cpuprofile cpu.out net/http

ok net/http 40.488s

分别保存了CPU和Memory Profile采样数据。

参数 说明 示例 -------------------+--------------------------------------+-------------- -cpuprofile 保存执行时间采样到指定文件 -cpuprofile cpu.out -memprofile 保存内存分配采样到指定文件 -memprofile mem.out -memprofilerate 内存分配采样起始值,默认为512KB -memprofilerate 1 -blockprofile 保存阻塞时间采样到指定文件 -blockprofile block.out -blockprofilerate 阻塞时间采样起始值,单位:ns

如果执行性能测试,可能须设置benchtime参数,以确保有足够的采样时间。

可使用交互模式查看,或用命令行直接输出单项结果。

$go tool pprof http.test mem.out

Entering interactive mode(type”help”for commands)

(pprof)top5

2128.96kB of 2128.96kB total( 100%) Dropped 261 nodes(cum10.64kB) Showing top 5 nodes out of 22(cum>=591.75kB) flat flat% sum% cum cum% 1025.02kB 48.15%48.15% 1025.02kB 48.15% net/http2/hpack.addDecoderNode 591.75kB 27.80%75.94% 591.75kB 27.80% crypto/elliptic.initTable 512.19kB 24.06% 100% 512.19kB 24.06% runtime.malg 0 0% 100% 591.75kB 27.80% crypto/elliptic.(*p256Point).p256BaseMult 0 0% 100% 591.75kB 27.80% crypto/elliptic.GenerateKey

  • flat:仅当前函数,不包括它调用的其他函数。
  • sum:列表前几行所占百分比的总和。
  • cum:当前函数调用堆栈累计。

默认输出信息的是alloc_space,也可以在命令行指定采样参数为alloc_objects。top命令可指定排序字段,比如“top5-cum”。

找出需要进一步查看的目标,使用peek命令列出调用来源。

(pprof)peek malg

2128.96kB of 2128.96kB total( 100%) Dropped 261 nodes(cum10.64kB) -----------------------------------------------------+------------- flat flat% sum% cum cum% calls calls% +context
-----------------------------------------------------+------------- 512.19kB 100% |runtime.newproc1 512.19kB 24.06%24.06% 512.19kB 24.06% |runtime.malg -----------------------------------------------------+-------------

在目标行上部会列出多个调用该目标的函数名称,以及各自的采样统计结果。

也可用list命令输出源码行统计样式,以便更直观地定位。

(pprof)list malg

Total:2.08MB ROUTINE========================runtime.malg in/usr/local/go/src/runtime/proc.go 512.19kB 512.19kB(flat,cum)24.06%of Total . . 2633:func malg(stacksize int32) *g{ 512.19kB 512.19kB 2634: newg:=new(g) . . 2635: if stacksize>=0{ . . 2636: stacksize=round2(_StackSystem+stacksize)

除文字模式外,还可输出svg图形,将其保存或用浏览器查看。

(pprof)web # 全部 (pprof)web malg # 以malg为主,精简输出结果

在OS X下查看svg须安装Graphviz,并将默认打开方式改为“浏览器”。

用命令行方式查看单项统计结果:

$go tool pprof-text-alloc_objects-cum http.test mem.out

64393542 of 68470362 total(94.05%) Dropped 199 nodes(cum342351) flat flat% sum% cum cum% 0 0% 0% 68452612 100% runtime.goexit 5136307 7.50% 7.50% 42942461 62.72% net/http.readRequest 0 0% 7.50% 31091053 45.41% testing.(*B).launch 0 0% 7.50% 31091053 45.41% testing.(*B).runN

相关参数,请查看“go tool pprof-h”。

在线采集检测数据须注入http/pprof包。

import( “net/http” _ “net/http/pprof” )

func main() { http.ListenAndServe(“:8080”,http.DefaultServeMux) }

如果使用ServerMux,可用mux.HandleFunc方法调用pprof里的相关函数。

用浏览器访问指定路径,就可看到不同的监测项。直接点击查看,或继续用命令行操作。

$go tool pprof http://localhost:8080/debug/pprof/heap?debug=1

必要时还可抓取数据,进行离线分析。

go tool pprof test mem.out